const path = require("path");
const fs = require("fs");
const { indexName } = require("../config");
const TurndownService = require("turndown");
const turndownService = new TurndownService({
  headingStyle: "atx", // 标题样式。	setext or atx    默认：setext
  // hr: "", //Any Thematic break    默认：* * *
  bulletListMarker: "-", //-, +, or *    默认：*
  // codeBlockStyle: "fenced", //缩进或围起来。 indented or fenced    默认：indented（如果使用fenced围起来，vuepress不识别console代码高亮语言而一直在控制台打印Language does not exist: console）
  // fence: "", //``` or ~~~    默认：```
  // emDelimiter: "", //_ or *    默认：_
  // strongDelimiter: "", //** or __    默认：**
  // linkStyle: "", //内联或引用。  inlined or referenced    默认：inlined
  // linkReferenceStyle: "", //完整, 折叠或快捷方式。 full, collapsed, or shortcut    默认：full
  // preformattedCode: "", //false or true    默认：false
});
turndownService.keep([
  "h1",
  "h2",
  "h3",
  "h4",
  "h5",
  "h6",
  "a",
  "img",
  "code",
  "pre",
]);

/**
 * 检测元素所属类型
 * Object.prototype.toString.call(*)的可能结果如下所示：
 * @example null             [object Null]
 * @example undefined        [object Undefined]
 * @example Symbol());       [object Symbol]
 * @example true             [object Boolean]
 * @example ''               [object String]
 * @example 1                [object Number]
 * @example []               [object Array]
 * @example {}               [object Object]
 * @example new Date()       [object Date]
 * @example new Function()   [object Function]
 * @example new RegExp()     [object RegExp]
 * @example new Error()      [object Error]
 * @example document         [object HTMLDocument]
 * @example window           [object global] window 是全局对象 global 的引用
 * @param {*} ele 待检测的对象、字符串、数组等
 * @returns {String} 元素类型（string、number、boolean、symbol、undefined、null、function、date、array、object、regexp、error、htmldocument、global）
 */
function typeOf(ele) {
  let endStr = Object.prototype.toString.call(ele);
  let type = endStr.split(" ")[1].slice(0, -1);
  return type;
}

/**
 * 递归创建目录(同步方法)
 * 注：nodejs不能一次性创建多层目录，需要递归处理
 * @param dirname 多层目录路径 示例： hello/a/b/c
 */
function mkdirsSync(dirname) {
  if (fs.existsSync(dirname)) {
    return true;
  } else {
    if (mkdirsSync(path.dirname(dirname))) {
      fs.mkdirSync(dirname);
      return true;
    }
  }
}
/**
 * 递归获取子路径
 * @param folderPath 多层目录路径 示例： hello/a/b/c
 * @param urls 多层路径记录
 */
async function getSubPaths(folderPath = "", urls = []) {
  const char = " ";
  const paths = await Promise.all(
    fs.readdirSync(folderPath).map(async (file, ind) => {
      const curPath = path.join(folderPath, file);
      const isDirectory = fs.lstatSync(curPath).isDirectory(); //是否是文件夹
      const cloneUrls = JSON.parse(JSON.stringify(urls));
      cloneUrls.push(file);
      if (isDirectory) {
        const children = await getSubPaths(curPath, cloneUrls);
        return {
          title: file,
          collapsable: false,
          children,
        };
      } else {
        // const [id, title] = cloneUrls.slice(-1)[0].split("_");
        return file === indexName
          ? ""
          : [
              cloneUrls.join("/"),
              cloneUrls.slice(-1)[0].replace("_", char).slice(0, -3),
            ];
        // return file === indexName ? "" : cloneUrls.join("/");
      }
    })
  );
  return sortPaths(paths, char);
}
/**
 * 把字符串和对象排序，如果有数字前缀，则根据数字前缀排序
 * @example
  const paths = [
    "",
    "1_one",
    {
      title: "3_分组3",
      collapsable: false,
      children: ["three/3-1.md", "three/3-2.md"],
    },
    {
      title: "2_分组2",
      collapsable: false,
      children: ["two/2-1", "two/2-2"],
    },
    "4_vue-press",
  ];
 */
function sortPaths(paths = [], char = " ") {
  paths.sort(function (a, b) {
    const isStrA = typeof a === "string";
    const isStrB = typeof b === "string";
    const titleA = isStrA ? a : Array.isArray(a) ? a[1] : a.title;
    const titleB = isStrB ? b : Array.isArray(b) ? b[1] : b.title;
    const numA = Number(titleA.split(char)[0]) || 0;
    const numB = Number(titleB.split(char)[0]) || 0;
    return numA - numB;
  });
  return paths;
}

/**
 * 函数未传必填参数时的校验
 * @param name string 参数名称
 */
function needParam(name) {
  throw new Error("请传入参数：" + name);
}

module.exports = {
  /**
   * 检测元素所属类型
   * @link
   */
  typeOf,

  /**
   * turndown 实例
   * @link 参数配置参考： https://www.mianshigee.com/project/domchristie-turndown/
   */
  turndownService,

  /**
   * 递归创建目录(同步方法)
   * 注：nodejs不能一次性创建多层目录，需要递归处理
   * @param dirname 多层目录路径 示例： hello/a/b/c
   * @link
   */
  mkdirsSync,

  /**
   * 递归获取子路径
   * @param folderPath 多层目录路径 示例： hello/a/b/c
   * @param urls 多层路径记录
   * @link
   */
  getSubPaths,

  /**
   * 将字符串第一个单词大写
   */
  upperFirst(str = "") {
    if (str) {
      return str[0].toUpperCase() + str.slice(1);
    }
    return str;
  },

  /**
   * 将字符串转为小驼峰
   */
  camelCase(str = "", isToBy = true) {
    str = str.replace(/_+|\/+|\\+/g, "_");
    str = str.replace(/{+/g, isToBy ? "By_" : "_").replace(/}+/g, "");
    str = str
      .split(/_+/)
      .map((it, ind) => {
        let firstChar = ind === 0 ? it[0].toLowerCase() : it[0].toUpperCase();
        return firstChar + it.slice(1);
      })
      .join("");
    return str;
  },

  /**
   * 写入文件
   * @param writePath string
   * @param writeStr string 写入的文件内容
   * @param encoding 编码格式
   * @return error 错误信息，如果没有错误，则为null
   */
  writeFileSync(writePath, writeStr, showSuccess = true, encoding = "utf-8") {
    const basename = path.basename(writePath);
    const isSuccess = mkdirsSync(writePath.replace(basename, ""));
    if (isSuccess) {
      const err = fs.writeFileSync(writePath, writeStr, encoding);
      if (err) {
        console.log(writePath + "写入失败", err);
      } else {
        showSuccess && console.log(writePath + "写入成功！");
      }
      return err;
    } else {
      console.log("创建文件目录失败");
      return { err: "创建文件目录失败" };
    }
  },

  /**
   * 往文件中固定的行写入数据，但不执行写入文件操作（同步）
   * @param file string 文件路径或文件数据
   * @param aimStr string 指定行的字符串，在其后添加一行
   * @param isFile boolean 是否是文件
   * @return 返回添加行数据之后的文件数据字符串
   */
  addToFileLineSync(file = "", aimStr = "", addLines = [], isFile = false) {
    const splitReg = /\r\n|\n|\r/gm;
    const fileStr = isFile ? fs.readFileSync(file, "utf8") : file;
    const lines = fileStr.split(splitReg);
    let ind =
      lines.findIndex((it) => it.replace(/ +/g, "").includes(aimStr)) + 1;
    if (ind === -1) {
      ind = lines.length - 1;
    }
    lines.splice(ind, 0, ...addLines);
    return lines.join("\r\n");
  },
};
